/**
 * 
 */
package com.google.code.netz.wfe;

import java.util.List;

import com.google.code.netz.wfe.api.ILifecycleHandler;
import com.google.code.netz.wfe.api.IWorkflowContext;
import com.google.code.netz.wfe.api.IWorkflowEngine;
import com.google.code.netz.wfe.api.WorkflowException;
import com.google.code.netz.wfe.events.EventManager;
import com.google.code.netz.wfe.events.TransitionEvent;
import com.google.code.netz.wfe.events.TransitionEvent.TransitionEventType;
import com.google.code.netz.wfe.model.ITask;
import com.google.code.netz.wfe.model.InputArc;
import com.google.code.netz.wfe.model.State;
import com.google.code.netz.wfe.model.Transition;

/**
 * @author <a href='mailto:rahul.thakur.xdev@gmail.com'>Rahul Thakur</a>
 * @since 1.0
 * @version $Id: TransitionLifecycleHandler.java 17 2009-02-09 13:08:49Z
 *          rahul.thakur.xdev $
 */
public class TransitionLifecycleHandler implements ILifecycleHandler<Transition<?>> {

	/**
	 * Mutex to lock state updates to the Transition.
	 */
	private static Object mutex = new Object();

	/**
	 * {@inheritDoc}
	 * 
	 * @see com.google.code.netz.wfe.api.ILifecycleHandler#resume(com.google.code.netz.wfe.model.IPetriNetEntity,
	 *      IWorkflowContext)
	 */
	@Override
	public void resume(Transition<?> entity, IWorkflowContext workflowContext) throws WorkflowException {
		// TODO Auto-generated method stub
		synchronized (mutex) {
			if (entity.getCurrentState() == State.STATE_SUSPENDED) {
				entity.setCurrentState(State.STATE_RUNNING);
				EventManager.getInstance().dispatchEvent(
						new TransitionEvent<Transition<?>>(entity, TransitionEventType.TRANSITION_ENABLED));
			} else
				throw new WorkflowException(String.format(
						"Transition %s could not be resumed, it is not in a suspended state.", entity.getLabel()));
		}
	}

	/**
	 * {@inheritDoc}
	 * 
	 * @see com.google.code.netz.wfe.api.ILifecycleHandler#start(com.google.code.netz.wfe.model.IPetriNetEntity,
	 *      IWorkflowContext)
	 */
	@Override
	public void start(Transition<?> entity, IWorkflowContext workflowContext) throws WorkflowException {
		IWorkflowEngine engine = workflowContext.getWorkflowEngine();
		// TODO Auto-generated method stub
		synchronized (mutex) {
			// TODO: Transition status should be updated in a synchronized block
			if (entity.getCurrentState() == State.STATE_ENABLED || entity.getCurrentState() == State.STATE_DEFAULT) {
				entity.setCurrentState(State.STATE_RUNNING);
				EventManager.getInstance().dispatchEvent(
						new TransitionEvent<Transition>(entity, TransitionEventType.TRANSITION_FIRED));
				// Run associated ITask
				ITask task = entity.getTask();
				if (null != task)
					task.execute(workflowContext);
				else
					System.out.println("No Task was specified for Transition : " + entity.getLabel());

				// all done - progress the Transition state to COMPLETED if it
				// was not an internal transition
				if (!entity.isInternal()) {
					// Remove Tokens from inputs
					List<InputArc<?>> inputs = entity.getInputs();
					// inputs are NULL in case of START Place node
					if (null != inputs) {
						for (InputArc<?> arc : inputs) {
							arc.getSource().removeToken();
						}
					}

					stop(entity, workflowContext);
				}
			} else
				throw new WorkflowException(String.format(
						"Transition %s could not be started, it is not in a default state. (Found state: %s)", entity
								.getLabel(), entity.getCurrentState().toString()));
		}
	}

	/**
	 * {@inheritDoc}
	 * 
	 * @see com.google.code.netz.wfe.api.ILifecycleHandler#stop(com.google.code.netz.wfe.model.IPetriNetEntity,
	 *      IWorkflowContext)
	 */
	@Override
	public void stop(Transition<?> entity, IWorkflowContext workflowContext) throws WorkflowException {
		// TODO Auto-generated method stub
		synchronized (mutex) {
			// TODO: Transition status should be updated in a synchronized block
			// TODO: Evaluated current state of the Transition,
			// if the Transition completed without error then the state should
			// be set to COMPLETED else should be set to ERROR
			if (entity.getCurrentState() == State.STATE_RUNNING) {
				entity.setCurrentState(State.STATE_COMPLETED);
				EventManager.getInstance().dispatchEvent(
						new TransitionEvent<Transition>(entity, TransitionEventType.TRANSITION_COMPLETED));

			} else
				throw new WorkflowException(String.format(
						"Transition %s could not be stopped, it is not currently running.", entity.getLabel()));
		}
	}

	/**
	 * {@inheritDoc}
	 * 
	 * @see com.google.code.netz.wfe.api.ILifecycleHandler#suspend(com.google.code.netz.wfe.model.IPetriNetEntity,
	 *      IWorkflowContext)
	 */
	@Override
	public void suspend(Transition<?> entity, IWorkflowContext workflowContext) throws WorkflowException {
		// TODO Auto-generated method stub
		synchronized (mutex) {
			// TODO: Transition status should be updated in a synchronized block
			if (entity.getCurrentState() == State.STATE_RUNNING) {
				entity.setCurrentState(State.STATE_SUSPENDED);
				EventManager.getInstance().dispatchEvent(
						new TransitionEvent<Transition>(entity, TransitionEventType.TRANSITION_SUSPENDED));
			} else
				throw new WorkflowException(String.format(
						"Transition %s could not be suspended, it is not currently running.", entity.getLabel()));
		}
	}

}
